home *** CD-ROM | disk | FTP | other *** search
/ CYBER.XPO.95 / CYBER.XPO.95 (Arsenal Computer).ISO / popreq / amiga1 / am291193.lha / src / addtoc.c
C/C++ Source or Header  |  1993-10-13  |  13KB  |  608 lines

  1. /*
  2.     addtoc.c    V1.0    29.08.1993
  3.  
  4.     Copyright (C)   1993    Jochen Wiedmann
  5.  
  6.     This program is free software; you can redistribute it and/or modify
  7.     it under the terms of the GNU General Public License as published by
  8.     the Free Software Foundation; either version 2 of the License, or
  9.     (at your option) any later version.
  10.  
  11.     This program is distributed in the hope that it will be useful,
  12.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.     GNU General Public License for more details.
  15.  
  16.     You should have received a copy of the GNU General Public License
  17.     along with this program; if not, write to the Free Software
  18.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  
  20.  
  21.     This scans a texinfo file and adds a table of contents to the relating
  22.     AmigaGuide and Ascii files. Note that they have to be created first and
  23.     MUST be up to date. Best way to ensure this is using a Makefile.
  24.  
  25.     Usage:  addtoc TFILE/A,GFILE/K,DFILE/K
  26.  
  27.     TFILE is the texinfo source, GFILE is the AmigaGuide file and DFILE is
  28.     the Ascii file. Files GFILE.new and DFILE.new are created.
  29.  
  30.     The texinfo file has to be in a special format: Each node (except the Top
  31.     node) MUST have a following line containing an @chapter, @section,
  32.     @subsection or @unnumbered command. The node commands MUST contain
  33.     nothing else than the node name.
  34.     Note that @info and @tex commands are ignored. In fact anything is
  35.     ignored, except for the node and sectioning commands.
  36.  
  37.     Author:      Jochen Wiedmann
  38.           Am Eisteich 9
  39.         72555 Metzingen (Germany)
  40.           Tel. 07123 / 14881
  41.  
  42.  
  43.     Computer:      Amiga 1200 (should run on any Amiga)
  44.  
  45.     Compiler:      Dice and Aztec-C (should run through SAS and gcc)
  46. */
  47.  
  48. #include <stdlib.h>
  49. #include <stdio.h>
  50. #include <string.h>
  51. #include <errno.h>
  52. #ifndef FALSE
  53. #define FALSE 0
  54. #endif
  55. #ifndef TRUE
  56. #define TRUE (!FALSE)
  57. #endif
  58. #ifndef HAVE_STRICMP
  59. #define stricmp strcasecmp
  60. #define strnicmp strncasecmp
  61. #endif
  62.  
  63.  
  64. /*
  65.     Maximum length of a line in the source file. Probably works with longer
  66.     lines, but this may not be guaranteed. Even the line numbering WILL
  67.     be damaged.
  68. */
  69. #define MAXLINE 1024    /*  Maximum length of a node name.  */
  70.  
  71.  
  72. /*
  73.     This is used to hold the information we get by scanning the texinfo
  74.     source. Each node is represented by exactly one node structure.
  75. */
  76. struct node
  77. { struct node *next;
  78.   char *name;
  79.   char *title;
  80.   int type;
  81. };
  82. #define TYPE_UNNUMBERED 0
  83. #define TYPE_CHAPTER    1
  84. #define TYPE_SECTION    2
  85. #define TYPE_SUBSECTION 3
  86.  
  87.  
  88.  
  89.  
  90. /*
  91.     The ignorespace() function removes trailing blanks from a line.
  92. */
  93. char *ignorespace(char *line)
  94.  
  95. { while (*line == ' '  ||  *line == '\t')
  96.   { ++line;
  97.   }
  98.   return(line);
  99. }
  100.  
  101.  
  102.  
  103.  
  104. /*
  105.     The salloc() function allocates memory for a string. Note, that it
  106.     removes trailing Line-Feeds.
  107. */
  108. char *salloc(char *str)
  109.  
  110. { char *ptr;
  111.   int len = strlen(str);
  112.  
  113.   while (len > 0  &&  str[len-1] == '\n')
  114.   { str[--len] = '\0';
  115.   }
  116.   if ((ptr = malloc(len+1))  !=  NULL)
  117.   { strcpy(ptr, str);
  118.   }
  119.   return(ptr);
  120. }
  121.  
  122.  
  123.  
  124.  
  125. /*
  126.     The memerror() function reports a memory error and terminates the
  127.     program.
  128. */
  129. void memerror(void)
  130.  
  131. { fprintf(stderr, "Out of memory!\n");
  132.   exit(20);
  133. }
  134.  
  135.  
  136.  
  137.  
  138. /*
  139.     The Scan() function scans the texinfo source file.
  140. */
  141. void Scan(struct node **first, char *tfile)
  142.  
  143. { FILE *fh;
  144.   struct node *node;
  145.   char line[MAXLINE+1];
  146.   char title[MAXLINE+1];
  147.   char *titleptr;
  148.   int lineno;
  149.   extern int errno;
  150.  
  151.   if ((fh = fopen(tfile, "r"))  ==  NULL)
  152.   { fprintf(stderr, "Cannot open %s as source file!\n", tfile);
  153.     exit(10);
  154.   }
  155.  
  156.   *first = NULL;
  157.   lineno = 0;
  158.   while (fgets(line, sizeof(line), fh)  !=  NULL)
  159.   { ++lineno;
  160.     if (strnicmp(line, "@node", 5)  ==  0           &&
  161.     fgets(title, sizeof(title), fh)  !=  NULL)
  162.     { int type;
  163.  
  164.       ++lineno;
  165.       type = -1;
  166.       if (strnicmp(title, "@unnumbered", 11)  ==  0)
  167.       { type = TYPE_UNNUMBERED;
  168.     titleptr = title+11;
  169.       }
  170.       else if (strnicmp(title, "@chapter", 8)  ==  0)
  171.       { type = TYPE_CHAPTER;
  172.     titleptr = title+8;
  173.       }
  174.       else if (strnicmp(title, "@section", 8)  ==  0)
  175.       { type = TYPE_SECTION;
  176.     titleptr = title+8;
  177.       }
  178.       else if (strnicmp(title, "@subsection", 11)  ==  0)
  179.       { type = TYPE_SUBSECTION;
  180.     titleptr = title+11;
  181.       }
  182.       else if (strnicmp(title, "@top", 4)  !=  0)
  183.       { fprintf(stderr, "Warning: Unknown sectioning command in line %d!\n",
  184.         lineno);
  185.     fprintf(stderr, "         Expected @chapter, @section, @subsection "
  186.             ", @unnumbered or @top.\n");
  187.       }
  188.       if (type != -1)
  189.       { if ((node = malloc(sizeof(*node)))  ==  NULL)
  190.     { memerror();
  191.     }
  192.     if ((node->name = salloc(ignorespace(line+5)))  ==  NULL   ||
  193.         (node->title = salloc(ignorespace(titleptr)))  ==  NULL)
  194.     { memerror();
  195.     }
  196.     node->next = NULL;
  197.     node->type = type;
  198.     *first = node;
  199.     first = &node->next;
  200.       }
  201.     }
  202.   }
  203.   if (errno)
  204.   { perror("addtoc");
  205.   }
  206.   fclose(fh);
  207. }
  208.  
  209.  
  210.  
  211.  
  212. /*
  213.     The myscan() function scans a string like @{"title" Link "name"} for
  214.     name.
  215. */
  216. char *myscan(char *line, char *name)
  217.  
  218. { line = ignorespace(line);
  219.   if (strncmp(line, "@{\"", 3)  !=  0)
  220.   { return(NULL);
  221.   }
  222.   line += 3;
  223.   while (*line != '\"'  &&  *line != '\0')
  224.   { line++;
  225.   }
  226.   if (*line == '\0')
  227.   { return(NULL);
  228.   }
  229.   ++line;
  230.   line = ignorespace(line);
  231.   if (strnicmp(line, "Link", 4)  !=  0)
  232.   { return(NULL);
  233.   }
  234.   line+=4;
  235.   line = ignorespace(line);
  236.   if (*(line++) != '\"')
  237.   { return(NULL);
  238.   }
  239.   while (*line != '\"'  &&  *line != '\0')
  240.   { *(name++) = *(line++);
  241.   }
  242.   if (strncmp(line, "\"}", 2)  !=  0)
  243.   { return(NULL);
  244.   }
  245.   *name = '\0';
  246.   return(line+2);
  247. }
  248.  
  249.  
  250.  
  251.  
  252. /*
  253.     The ScanGuide() function scans the AmigaGuide file, removes the menu
  254.     in the top node and replaces it by the table of contents.
  255. */
  256. void ScanGuide(struct node *first, char *gtitle)
  257.  
  258. { FILE *fhin;
  259.   FILE *fhout;
  260.   char *newtitle;
  261.   struct node *node;
  262.   int InMain;
  263.   int lineno;
  264.   char line[MAXLINE+1];
  265.   char name[MAXLINE+1];
  266.  
  267.   /*
  268.       Opening files
  269.   */
  270.   if ((newtitle = malloc(strlen(gtitle)+5))  ==  NULL)
  271.   { memerror();
  272.   }
  273.   sprintf(newtitle, "%s.new", gtitle);
  274.  
  275.   if ((fhin = fopen(gtitle, "r"))  ==  NULL)
  276.   { fprintf(stderr, "Cannot open %s as input!\n", gtitle);
  277.     exit(10);
  278.   }
  279.   if ((fhout = fopen(newtitle, "w"))  ==  NULL)
  280.   { fprintf(stderr, "Cannot open %s as output!\n", newtitle);
  281.     exit(11);
  282.   }
  283.  
  284.   /*
  285.       Looking for the Top Node
  286.   */
  287.   InMain = FALSE;
  288.   lineno = 0;
  289.   while(fgets(line, sizeof(line), fhin)  !=  NULL)
  290.   { ++lineno;
  291.     if (strnicmp(line, "@Node Main", 10)  ==  0)
  292.     { InMain = TRUE;
  293.     }
  294.     else if (strnicmp(line, "@EndNode", 8)  ==  0)
  295.     { InMain = FALSE;
  296.     }
  297.     if (InMain  &&  strnicmp(ignorespace(line), "@{\"", 3) == 0)
  298.     { if (myscan(line, name)  ==  NULL)
  299.       { fprintf(stderr,
  300.         "Error: Cannot scan line %d of %s (unknown format)!\n",
  301.         lineno, gtitle);
  302.       }
  303.       else
  304.       { int blanks;
  305.  
  306.     fputs(line, fhout);
  307.     blanks = ignorespace(line)-line;
  308.     for (node = first;  node != NULL;  node = node->next)
  309.     { if (strncmp(name, node->name, strlen(name)) == 0  &&
  310.           (node->type == TYPE_CHAPTER  ||  node->type == TYPE_UNNUMBERED))
  311.       { break;
  312.       }
  313.     }
  314.  
  315.     node = node->next;
  316.     while (node != NULL  &&  node->type != TYPE_CHAPTER  &&
  317.            node->type != TYPE_UNNUMBERED)
  318.     { switch (node->type)
  319.       { case TYPE_UNNUMBERED:
  320.         case TYPE_CHAPTER:
  321.           break;
  322.         case TYPE_SECTION:
  323.           fprintf(fhout, "    ");
  324.           break;
  325.         case TYPE_SUBSECTION:
  326.           fprintf(fhout, "        ");
  327.           break;
  328.       }
  329.       fprintf(fhout, "@{\" %s \" Link \"%s\"}\n", node->title,
  330.           node->name);
  331.       node = node->next;
  332.     }
  333.       }
  334.     }
  335.     else
  336.     { fputs(line, fhout);
  337.     }
  338.   }
  339.   if (errno)
  340.   { perror("addtoc");
  341.   }
  342.   fclose(fhin);
  343.   fclose(fhout);
  344. }
  345.  
  346.  
  347.  
  348.  
  349. /*
  350.     The subcmp() function checks for len occurences of c. Result is 0, if
  351.     there are, nonzero otherwise.
  352. */
  353. int subcmp(char *line, char c, int len)
  354.  
  355. { int i;
  356.  
  357.   for (i = 0;  i < len;  i++)
  358.   { if (line[i] != c)
  359.     { return(line[i]-c);
  360.     }
  361.   }
  362.   return(0);
  363. }
  364.  
  365.  
  366.  
  367.  
  368. /*
  369.     The ScanDoc function scans the Ascii document and adds the table of
  370.     contents and section numbers.
  371. */
  372. void ScanDoc(struct node *first, char *dtitle)
  373.  
  374. { FILE *fhin, *fhout;
  375.   char *newtitle;
  376.   int lineno;
  377.   int chapter, section, subsection;
  378.   int tocdone;
  379.   char line[MAXLINE+1];
  380.   char subline[MAXLINE+1];
  381.   static char subchar[3] = "*=-";
  382.   char c;
  383.  
  384.   /*
  385.       Opening files
  386.   */
  387.   if ((newtitle = malloc(strlen(dtitle)+5))  ==  NULL)
  388.   { memerror();
  389.   }
  390.   sprintf(newtitle, "%s.new", dtitle);
  391.  
  392.   if ((fhin = fopen(dtitle, "r"))  ==  NULL)
  393.   { fprintf(stderr, "Cannot open %s as input!\n", dtitle);
  394.     exit(10);
  395.   }
  396.   if ((fhout = fopen(newtitle, "w"))  ==  NULL)
  397.   { fprintf(stderr, "Cannot open %s as output!\n", newtitle);
  398.     exit(11);
  399.   }
  400.  
  401.  
  402.   /*
  403.       Scanning for nodes
  404.   */
  405.   tocdone = FALSE;
  406.   lineno = 0;
  407.   chapter = section = subsection = 0;
  408.   while (fgets(line, sizeof(line), fhin)  !=  NULL)
  409.   { ++lineno;
  410.     if (first != NULL  &&
  411.     strncmp(line, first->title, strlen(first->title))  ==  0   &&
  412.     fgets(subline, sizeof(subline), fhin)  !=  NULL)
  413.     { ++lineno;
  414.       switch(first->type)
  415.       { case TYPE_UNNUMBERED:
  416.     case TYPE_CHAPTER:
  417.       c = subchar[0];
  418.       break;
  419.     case TYPE_SECTION:
  420.       c = subchar[1];
  421.       break;
  422.     case TYPE_SUBSECTION:
  423.       c = subchar[2];
  424.       break;
  425.       }
  426.       if(subcmp(subline, c, strlen(first->title))  ==  0)
  427.       { int i;
  428.     int level;
  429.     struct node *node;
  430.     char number[128];
  431.  
  432.     /*
  433.         Add the table of contents, if we have found the first
  434.         node.
  435.     */
  436.     if (!tocdone)
  437.     { int chapter, section, subsection;
  438.  
  439.       chapter = section = subsection = 0;
  440.       for (node = first;  node != NULL;  node = node->next)
  441.       { if (node->type == TYPE_CHAPTER  ||  node->type == TYPE_UNNUMBERED)
  442.         { putc('\n', fhout);
  443.         }
  444.         switch (node->type)
  445.         { case TYPE_CHAPTER:
  446.         ++chapter;
  447.         section = subsection = 0;
  448.         fprintf(fhout, "%d. ", chapter);
  449.         break;
  450.           case TYPE_UNNUMBERED:
  451.         break;
  452.           case TYPE_SECTION:
  453.         ++section;
  454.         subsection = 0;
  455.         fprintf(fhout, "  %d. ", section);
  456.         break;
  457.           case TYPE_SUBSECTION:
  458.         ++subsection;
  459.         fprintf(fhout, "    %d. ", subsection);
  460.         break;
  461.         }
  462.         fprintf(fhout, "%s\n", node->title);
  463.       }
  464.       fprintf(fhout, "\n\n\n");
  465.       tocdone = TRUE;
  466.     }
  467.  
  468.     switch(first->type)
  469.     { case TYPE_UNNUMBERED:
  470.         strcpy(number, "");
  471.         level = 0;
  472.         break;
  473.       case TYPE_CHAPTER:
  474.         ++chapter;
  475.         section = subsection = 0;
  476.         sprintf(number, "%d. ", chapter);
  477.         level = 0;
  478.         break;
  479.       case TYPE_SECTION:
  480.         ++section;
  481.         subsection = 0;
  482.         sprintf(number, "%d.%d. ", chapter, section);
  483.         level = 1;
  484.         break;
  485.       case TYPE_SUBSECTION:
  486.         ++subsection;
  487.         sprintf(number, "%d.%d.%d. ", chapter, section, subsection);
  488.         level = 2;
  489.         break;
  490.     }
  491.     fprintf(fhout, "%s%s", number, line);
  492.     for (i = 0;  i < strlen(number);  i++)
  493.     { putc((int) subchar[level], fhout);
  494.     }
  495.     fputs(subline, fhout);
  496.     first = first->next;
  497.       }
  498.       else
  499.       { fputs(line, fhout);
  500.     fputs(subline, fhout);
  501.       }
  502.     }
  503.     else
  504.     { fputs(line, fhout);
  505.     }
  506.   }
  507.   if (first != NULL)
  508.   { fprintf(stderr, "Missing item, probably different text in header "
  509.             "and menu:\n%s\n", first->title);
  510.   }
  511.   if (errno)
  512.   { perror("addtoc");
  513.   }
  514.   fclose(fhin);
  515.   fclose(fhout);
  516. }
  517.  
  518.  
  519.  
  520.  
  521. /*
  522.     This prints the usage information and terminates.
  523. */
  524. void Usage(void)
  525.  
  526. { fprintf(stderr,
  527.     "Usage: addtoc TFILE/A,GFILE/K,DFILE/K\n\n"
  528.     "TFILE is the texinfo source file.\n"
  529.     "GFILE is the AmigaGuide file created from TFILE and DFILE the "
  530.     "corresponding\n"
  531.     "Ascii file. <GFILE>.new and <TFILE>.new, respectively, are created,\n"
  532.     "if the latter options are present.\n\n");
  533.   exit(1);
  534. }
  535.  
  536.  
  537.  
  538.  
  539. /*
  540.     This is main(). Does nothing except processing the arguments and calling
  541.     the Scan... functions.
  542. */
  543. void main(int argc, char *argv[])
  544.  
  545. { char *tfile, *gfile, *dfile;
  546.   struct node *first;
  547.   int i;
  548.  
  549. #ifdef DEBUG
  550.   tfile = "/Amiga-FAQ.texinfo";
  551.   gfile = "/Amiga-FAQ.guide";
  552.   dfile = "/Amiga-FAQ.doc";
  553. #else
  554.   if (argc < 2)
  555.   { Usage();
  556.   }
  557.  
  558.   tfile = NULL;
  559.   gfile = NULL;
  560.   dfile = NULL;
  561.  
  562.   for (i = 1;  i < argc;  i++)
  563.   { if (stricmp(argv[i], "gfile")  ==  0)
  564.     { if (++i == argc  ||  gfile != NULL)
  565.       { Usage();
  566.       }
  567.       gfile = argv[i];
  568.     }
  569.     else if (strnicmp(argv[i], "gfile=", 6)  ==  0)
  570.     { if (gfile != NULL)
  571.       { Usage();
  572.       }
  573.       gfile = &argv[i][6];
  574.     }
  575.     else if (stricmp(argv[i], "dfile")  ==  0)
  576.     { if (++i == argc  ||  dfile != NULL)
  577.       { Usage();
  578.       }
  579.       dfile = argv[i];
  580.     }
  581.     else if (strnicmp(argv[i], "dfile=", 6)  ==  0)
  582.     { if (dfile != NULL)
  583.       { Usage();
  584.       }
  585.       dfile = &argv[i][6];
  586.     }
  587.     else
  588.     { if (tfile != NULL)
  589.       { Usage();
  590.       }
  591.       tfile = argv[i];
  592.     }
  593.   }
  594.   if (tfile == NULL)
  595.   { Usage();
  596.   }
  597. #endif    /*  !DEBUG   */
  598.  
  599.  
  600.   Scan(&first, tfile);
  601.   if (gfile)
  602.   { ScanGuide(first, gfile);
  603.   }
  604.   if (dfile)
  605.   { ScanDoc(first, dfile);
  606.   }
  607. }
  608.